package com.orifine.dao.parser;

import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import com.bowos.zmado.model.Post;
import com.bowos.zmado.model.User;


public class SqlOgnlParser {
	private String sql;
	private StringBuffer sqlBuff;
	private List<SqlOgnlModel> sqlOgnlModelList = new ArrayList<SqlOgnlModel>();

	public SqlOgnlParser(String sql){
		this.sql = sql;
		this.sqlBuff = new StringBuffer(sql);
		osgnParse();
	}
	
	private void osgnParse() {
		Matcher stringMatcher = STRING_PATTERN.matcher(sqlBuff);
		Matcher ognlMatcher = OGNL_PATTERN.matcher(sqlBuff);

		int state = 0;
		for (int bufpos = 0; stringMatcher.find(bufpos);) {
			if(state == 0){
				if (stringMatcher.group().equals("\'")) {
					state = 1;
				} else if (stringMatcher.group().equals("\"")) {
					state = 2;
				} else if(stringMatcher.group().equals("#{")) {
					if(state == 0){
						if(ognlMatcher.find(stringMatcher.start())){
							String expression = ognlMatcher.group(1);
							sqlBuff.delete(ognlMatcher.start(), ognlMatcher.end());
							bufpos = ognlMatcher.start();
							sqlOgnlModelList.add(new SqlOgnlModel(expression, bufpos));
							continue;
						} else {
							throw new RuntimeException("#{}表达式不正确");
						}
					}
				}
			} else if(state == 1){
				if (stringMatcher.group().equals("\'")) {
					state = 0;
				}
			} else if(state == 2){
				if (stringMatcher.group().equals("\"")) {
					state = 0;
				}
			}
			
			bufpos = stringMatcher.end();
		}
	}
	
	public String toString(){
		return sql;
	}
	
	public String toString(Map<String, Object> directory, Object... args){
		StringBuffer sqlBuff = new StringBuffer(this.sqlBuff);
		int offset = 0;
		
		for(SqlOgnlModel sqlOgnlModel : sqlOgnlModelList){
			Object ObjectValue = directory != null?SqlOgnl.get(sqlOgnlModel.getExpression(), directory, args):SqlOgnl.get(sqlOgnlModel.getExpression(), args);
			String value;
			if(ObjectValue instanceof Collection){
				StringBuffer out = new StringBuffer();
				boolean isFirst = true;
				for(Object o:(Collection<?>)ObjectValue){
					if(isFirst){
						out.append(o.toString());
						isFirst = false;
					} else {
						out.append(',').append(o.toString());
					}
				}
				value = out.toString();
				
			} else if(ObjectValue instanceof Object[]){
				StringBuffer out = new StringBuffer();
				boolean isFirst = true;
				for(Object o:(Object[])ObjectValue){
					if(isFirst){
						out.append(o.toString());
						isFirst = false;
					} else {
						out.append(',').append(o.toString());
					}
				}
				value = out.toString();
			} else {
				if(ObjectValue == null){
					throw new NullPointerException(sqlOgnlModel.getExpression());
				}
				value = ObjectValue.toString();
			}
			sqlBuff.insert(sqlOgnlModel.getPosition() + offset, value);
			offset += value.length();
		}
		return sqlBuff.toString();
	}
	
	public String toString(Object... args){
		return toString(null, args);
	}
	
	private static final Pattern STRING_PATTERN = Pattern.compile("(?:\\\\\\\\|\\\\\\'|\\\"|\\\'|\"|'|#\\{)");
	private static final Pattern OGNL_PATTERN = Pattern.compile("#\\{([$]?[\\w\\.]+)\\}(?:\\{\\s*(\\w+|[\"][^\"]+[\"]|['][^']+['])\\s*:\\s*(\\w+|[\"][^\"]+[\"]|['][^']+['])\\s*(?:,\\s*(\\w+|[\"][^\"]+[\"]|['][^']+['])\\s*:\\s*(\\w+|[\"][^\"]+[\"]|['][^']+['])\\s*)*\\})?");
	
	public static String parse(String sql, Object... args){
		return new SqlOgnlParser(sql).toString(args);
	}
	
	public static String parse(String sql, Map<String, Object> directory, Object[] args){
		return new SqlOgnlParser(sql).toString(directory, args);
	}
	
	public static void main(String[] args) throws Exception {
		//parse("select abd #{user.id}{hello:world}sdfsf", root)
//		Matcher matcher = Pattern.compile("#\\{([$?][\\w\\.]+)\\}(?:\\{\\s*(?:\\w+|[\"']\\w+[\"'])\\s*:\\s*(?:\\w+|[\"']\\w+[\"'])\\s*(?:,\\s*(?:\\w+|[\"']\\w+[\"'])\\s*:\\s*(?:\\w+|[\"']\\w+[\"'])\\s*)*\\})?").matcher("select abd #{$1.user.id}{'hello':'world', obj:\"fuck\"}sdfsf");
//		while(matcher.find()){
//			System.out.println(matcher.group());
//		}
		
		User user = new User();
		user.setUsername("dong");
		user.setId(1);
		
		Post post = new Post();
		post.setAuthor(user);
		post.setId(2);
//		System.out.println(Ognl.getValue("author.username", post));
		
//		System.out.println(SqlOgnl.get("id", user, post));
		System.out.println(parse("select abd #{author.username}{'hello':'world', obj:\",\"}sdfsf", post));
	}
}
